package com.iris.live.services.config;

import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.annotation.PreDestroy;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * Created by Xin on 7/8/2016.
 */
@Configuration
@EnableJpaRepositories(
        basePackages = "com.iris.live.services.data.repositories",
        entityManagerFactoryRef = "entityManagerFactory",
        transactionManagerRef = "transactionManager"
)
@EnableTransactionManagement
public class DbConfig {

    @Autowired
    private Environment environment;

    @Bean(name = "transactionManager")
    @Autowired
    public JpaTransactionManager getTransactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory emFactory) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(emFactory);
        return txManager;
    }

    @Bean(name = "entityManagerFactory", destroyMethod = "close")
    @Autowired
    public EntityManagerFactory getEntityManagerFactory(@Qualifier("dataSource") DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(dataSource);
        factory.setPackagesToScan(new String[]{"com.iris.live.services.data"});
        factory.setJpaProperties(this.getHibernateProperties());
        factory.setPersistenceProvider(new HibernatePersistenceProvider());
        factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    @Bean(name = "dataSource")
    public DataSource getDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(this.environment.getRequiredProperty("db.driverClassName"));
        dataSource.setUrl(this.environment.getRequiredProperty("db.url"));
        dataSource.setUsername(this.environment.getRequiredProperty("db.username"));
        dataSource.setPassword(this.environment.getRequiredProperty("db.password"));
        dataSource.setConnectionProperties(this.getConnectionProperties());
        return dataSource;
    }

    private Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", this.environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", this.environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", this.environment.getRequiredProperty("hibernate.format_sql"));
        return properties;
    }

    private Properties getConnectionProperties() {
        Properties properties = new Properties();
        properties.put("maxActive", this.environment.getRequiredProperty("jdbc.maxActive"));
        properties.put("maxIdle", this.environment.getRequiredProperty("jdbc.maxIdle"));
        properties.put("maxWait", this.environment.getRequiredProperty("jdbc.maxWait"));
        properties.put("logAbandoned", this.environment.getRequiredProperty("jdbc.logAbandoned"));
        properties.put("removeAbandoned", this.environment.getRequiredProperty("jdbc.removeAbandoned"));
        properties.put("removeAbandonedTimeout", this.environment.getRequiredProperty("jdbc.removeAbandonedTimeout"));
        return properties;
    }

    @PreDestroy
    public void tearDown() {
        try {
            DriverManager.deregisterDriver(DriverManager.getDriver(this.environment.getRequiredProperty("db.url")));
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
